package com.googlecode.gendevcode.service.impl;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;

import com.googlecode.gendevcode.common.Cache;
import com.googlecode.gendevcode.model.ProjectXml;
import com.googlecode.gendevcode.model.ServiceConfigXml;
import com.googlecode.gendevcode.model.pdm.TablePdmXml;
import com.googlecode.gendevcode.model.pdm.ViewPdmXml;
import com.googlecode.gendevcode.service.GenCodeFilesService;
import com.googlecode.gendevcode.service.GenCodeService;
import com.googlecode.gendevcode.service.PdmService;
import com.googlecode.gendevcode.service.ProjectConfigService;
import com.googlecode.gendevcode.service.basic.ServiceSupport;

/**
 * 生成代码实现类
 * @author devilishking
 *
 */
public class GenCodeServiceImpl extends ServiceSupport<GenCodeServiceImpl>
								implements GenCodeService {
	//region 字典
	/**
	 * 生成级别：Spring的hibernate配置文件
	 */
	protected final String GENLEVEL_HIBERNATE_XML = "applicationContext-hibernate.xml";
	/**
	 * 生成级别：Spring的service配置文件
	 */
	protected final String GENLEVEL_SERVICE_XML = "applicationContext-service.xml";
	/**
	 * 生成级别：字典文件
	 */
	protected final String GENLEVEL_DICTIONARY_XML = "dictionary.xml";
	/**
	 * 生成级别：全部
	 */
	protected final String GENLEVEL_ALL = "all";
	//endregion
	
	/**
	 * 生成代码
	 */
	public void genCode() throws Exception {		
		while(true){
			List<ProjectXml> projectXmlList = Cache.getInstance().getProjectXmlList();
			System.out.println();
			System.out.println("项目列表");
			for(int i = 0; i < projectXmlList.size(); i++){
				ProjectXml projectXml = projectXmlList.get(i);
				System.out.println((new StringBuffer()).append("[").append(i).append("]")
													   .append(projectXml.getCnName())
													   .toString());
			}
			int projectIndex = FLAG_END;
			while(true){
				System.out.println();
				projectIndex = inputInt(String.format("请输入项目号: ('%0$s'退出): ", FLAG_END));
				if (FLAG_END == projectIndex || projectIndex < projectXmlList.size()){
					break;
				}
				else{
					System.out.println(String.format("不存在项目[%0$s],请重新输入!", projectIndex));
				}
			}
			if (FLAG_END == projectIndex){
				break;
			}
			else{
				genCode(projectXmlList.get(projectIndex));
			}
		}
	}

	/**
	 * 生成代码
	 * @param projectXml 项目信息
	 */
	private void genCode(ProjectXml projectXml) throws Exception{
		File pdmFile = new File(projectXml.getPdmPath());
		if (!pdmFile.exists() || !pdmFile.isFile()){
			System.out.println();
			System.out.println(String.format("[%0$s]项目的PDM文件不存在或PDM文件路径不是有文件! (PDM文件路径: %1$s)", 
											 projectXml.getName(), projectXml.getPdmPath()));
		}
		else{
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();    
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = null;
			try{
				doc = db.parse(pdmFile);
			}
			catch(Exception e){
				System.out.println();
				System.out.println(String.format("[%0$s]项目的PDM文件为无效文件! (PDM文件路径: %1$s)\r\n详细错误信息: %2$s", 
												 projectXml.getName(),
												 projectXml.getPdmPath(),
												 e.getMessage()));
			}			
			List<ViewPdmXml> viewList = new ArrayList<ViewPdmXml>();
			Map<String, ViewPdmXml> viewMap = new HashMap<String, ViewPdmXml>();
			Map<String, List<String>> tableIdListMap = new HashMap<String, List<String>>();
			Map<String, TablePdmXml> tablePdmXmlMap = new HashMap<String, TablePdmXml>();
			Map<String, TablePdmXml> tablePdmXmlByCodeMap = new HashMap<String, TablePdmXml>();
			
			PdmService pdmService = Cache.getInstance().getBean(ServiceConfigXml.ID_PDM, PdmService.class);
			pdmService.setViewTabelId(viewList, viewMap, tableIdListMap, doc);
			if (viewList.isEmpty()){
				System.out.println();
				System.out.println(String.format("[%0$s]项目的PDM文件为空文件! (PDM文件路径: %1$s)", 
												 projectXml.getName(),
												 projectXml.getPdmPath()));
			}
			else{
				pdmService.setTableInfo(tablePdmXmlMap, tablePdmXmlByCodeMap, viewList, tableIdListMap, doc);
				if (tablePdmXmlMap.isEmpty()){
					System.out.println();
					System.out.println(String.format("[%0$s]项目的PDM文件内没有任何表! (PDM文件路径: %1$s)", 
													 projectXml.getName(),
													 projectXml.getPdmPath()));
				}
				else{
					List<String> genLevelList = getGenLevelList(projectXml);
					List<TablePdmXml> tablePdmXmlList = getTablePdmXmlList(viewList,
																		   tableIdListMap,
																		   tablePdmXmlMap,
																		   tablePdmXmlByCodeMap);
					genFiles(genLevelList, tablePdmXmlList, viewMap, projectXml);					
					System.out.println();
					System.out.println("======生成成功!======");
					System.out.println();
				}
			}			
		}
	}

	/**
	 * 获得项目生成级别列表
	 * @param projectXml 项目信息
	 * @return
	 * @throws Exception
	 */
	private List<String> getGenLevelList(ProjectXml projectXml) throws Exception{
		List<String> genLevelList = new ArrayList<String>();
		ProjectConfigService projectConfigService = Cache.getInstance().getBean(ServiceConfigXml.ID_PROJECTCONFIG,
																				projectXml.getType(),
																			    ProjectConfigService.class);
		List<String> defineGenLevelList = projectConfigService.getGenLevelList();
		defineGenLevelList.add(GENLEVEL_HIBERNATE_XML);
		defineGenLevelList.add(GENLEVEL_SERVICE_XML);
		defineGenLevelList.add(GENLEVEL_DICTIONARY_XML);
		
		System.out.println();
		System.out.println("生成级别");
		for(int i = 0; i < defineGenLevelList.size(); i++){
			System.out.println((new StringBuffer()).append("[").append(i).append("]")
												   .append(defineGenLevelList.get(i))
												   .toString());
		}
		System.out.println((new StringBuffer()).append("[").append(defineGenLevelList.size()).append("]")
											   .append(GENLEVEL_ALL)
											   .toString());
		
		while(genLevelList.isEmpty()){
			String classIndexStr = inputStr(String.format("请输入生成级别号(可多选,以','间隔): %0$s: ", defineGenLevelList.size()), 
										    String.valueOf(defineGenLevelList.size()));
			String[] classIndexArr = classIndexStr.split(",");
			try{
				for(String classIndexStrTmp : classIndexArr){
					int classIndex = Integer.parseInt(classIndexStrTmp);
					if (classIndex == defineGenLevelList.size()){
						genLevelList.clear();
						genLevelList.addAll(defineGenLevelList);
						break;
					}
					else{
						genLevelList.add(defineGenLevelList.get(classIndex));
					}
				}
			}
			catch(Exception e){
				genLevelList.clear();
				System.out.println(String.format("生成级别号[%0$s]含有错误的值!", classIndexStr));
			}
		}
		return genLevelList;
	}

	/**
	 * 获取待生成的表信息列表
	 * @param viewList 		 	        视图列表<视图信息>
	 * @param tableIdListMap	        表和视图的关联关系集合<视图编号, List<表编号>>
	 * @param tablePdmXmlMap	        表信息集合<表编号, 表信息>
	 * @param tablePdmXmlByCodeMap 表信息集合<表编码, 表信息>
	 * @return
	 */
	private List<TablePdmXml> getTablePdmXmlList(List<ViewPdmXml> viewList,
												 Map<String, List<String>> tableIdListMap,
												 Map<String, TablePdmXml> tablePdmXmlMap,
												 Map<String, TablePdmXml> tablePdmXmlByCodeMap) {
		List<TablePdmXml> returnTablePdmXmlList = new ArrayList<TablePdmXml>();
		Integer type = -1;
		while(true){
			System.out.println();
			type = inputInt("请选择生成PDM方式: ('0'按视图生成; '1'按指定表生成): ");
			if (type != 0 && type != 1){
				System.out.println(String.format("不存在[%0$s]的生成PDM方式!", type));
			}
			else{
				break;
			}
		}
		if (0 == type){
			System.out.println();
			System.out.println("视图列表");
			for(int i = 0; i < viewList.size(); i++){
				ViewPdmXml viewPdmXml = viewList.get(i);
				System.out.println((new StringBuffer()).append("[").append(i).append("]")
													   .append(viewPdmXml.getName()));
			}
			List<String> viewIdList = new ArrayList<String>();
			while(viewIdList.isEmpty()){
				String viewIndexs = "";
				try{
					viewIndexs = inputStr("请输入视图号(可多选,以','间隔): ");
					String[] viewIndexArr = viewIndexs.split(",");
					for(String viewIndex : viewIndexArr){
						viewIdList.add(viewList.get(Integer.parseInt(viewIndex)).getId());
					}
				}
				catch(Exception e){
					viewIdList.clear();
					System.out.println(String.format("视图号[%0$s]中含有错误的值: ", viewIndexs));
				}
			}
			for(String viewId : viewIdList){
				List<String> tableIdList = tableIdListMap.get(viewId);
				for(String tableId : tableIdList){
					returnTablePdmXmlList.add(tablePdmXmlMap.get(tableId));
				}
			}
		}
		else{
			String tableNames = null;
			while(returnTablePdmXmlList.isEmpty()){
				try{
					tableNames = inputStr("请输入表名(可多选,以','间隔): ");
					String[] tableNameArr = tableNames.split(",");
					for(String tableName : tableNameArr){
						TablePdmXml tablePdmXml = tablePdmXmlByCodeMap.get(tableName);
						if (tablePdmXml == null){
							throw new Exception();
						}
						else{
							returnTablePdmXmlList.add(tablePdmXml);
						}
					}
				}
				catch(Exception e){
					System.out.println(String.format("表名[%0$s]中含有错误的值: ", tableNames));
				}
			}
		}		
		return returnTablePdmXmlList;
	}
	
	/**
	 * 生成文件
	 * @param genLevelList    项目生成级别列表	  
	 * @param tablePdmXmlList 待生成的表信息列表
	 * @param viewMap	                视图集合<视图编号, 视图信息>
	 * @param projectXml	     项目信息
	 * @throws Exception
	 */
	private void genFiles(List<String> genLevelList, 
						  List<TablePdmXml> tablePdmXmlList,
						  Map<String, ViewPdmXml> viewMap,
						  ProjectXml projectXml) throws Exception{
		GenCodeFilesService genCodeFilesService = Cache.getInstance().getBean(ServiceConfigXml.ID_GENCODEFILES, projectXml.getType(), GenCodeFilesService.class);
		for(String genLevel : genLevelList){
			if (GENLEVEL_HIBERNATE_XML.equals(genLevel)){
				genCodeFilesService.genHibernateXml(tablePdmXmlList, viewMap, projectXml);
			}
			else if (GENLEVEL_SERVICE_XML.equals(genLevel)){
				genCodeFilesService.genServiceXml(tablePdmXmlList, viewMap, projectXml);
			}
			else if (GENLEVEL_DICTIONARY_XML.equals(genLevel)){
				genCodeFilesService.genDictionaryXml(tablePdmXmlList, viewMap, projectXml);
			}
			else{
				genCodeFilesService.genCodeFilesXml(tablePdmXmlList, viewMap, genLevel, projectXml);
			}
		}
	}
}